package org.example.analysis.service;

import cn.hutool.core.collection.CollectionUtil;
import lombok.extern.slf4j.Slf4j;
import org.example.analysis.dao.CodeAnalysisDao;
import org.example.analysis.mapper.EntryPointInfoMapper;
import org.example.analysis.mapper.JavaClassInfoMapper;
import org.example.analysis.mapper.JavaMethodInfoMapper;
import org.example.analysis.mapper.ProjectInfoMapper;
import org.example.analysis.model.entity.JavaClassInfo;
import org.example.analysis.model.entity.JavaMethodInfo;
import org.example.analysis.model.entity.ProjectInfo;
import org.example.analysis.model.entity.EntryPointInfo;
import org.example.analysis.util.MybatisUtil;

import java.util.Collections;
import java.util.List;

/**
 * 代码分析服务
 */
@Slf4j
public class CodeAnalysisDbService {
    private final CodeAnalysisDao codeAnalysisDao;
    private final ProjectInfoMapper  projectManager;
    private final EntryPointInfoMapper entryPointInfoMapper;
    private final JavaClassInfoMapper javaClassInfoMapper;
    private final JavaMethodInfoMapper javaMethodInfoMapper;
    
    public CodeAnalysisDbService() {
        this.codeAnalysisDao = new CodeAnalysisDao();
        this.projectManager = MybatisUtil.getMapper(ProjectInfoMapper.class);
        this.entryPointInfoMapper = MybatisUtil.getMapper(EntryPointInfoMapper.class);
        this.javaClassInfoMapper = MybatisUtil.getMapper(JavaClassInfoMapper.class);
        this.javaMethodInfoMapper = MybatisUtil.getMapper(JavaMethodInfoMapper.class);
    }
    
    /**
     * 保存项目信息
     *
     * @param projectInfo 项目信息
     */
    public void saveProjectInfo(ProjectInfo projectInfo) {
        if (projectInfo == null) {
            throw new IllegalArgumentException("项目信息不能为空");
        }
        
        if (projectInfo.getProjectName() == null || projectInfo.getProjectName().trim().isEmpty()) {
            throw new IllegalArgumentException("项目名称不能为空");
        }
        
        try {
            codeAnalysisDao.saveProjectInfo(projectInfo);
            log.info("保存项目信息成功: {}", projectInfo.getProjectName());
        } catch (Exception e) {
            log.error("保存项目信息失败: {}", projectInfo.getProjectName(), e);
            throw new RuntimeException("保存项目信息失败", e);
        }
    }
    /**
     * 获取项目信息
     *
     * @param projectName 项目名称
     * @return 项目信息
     */
    public ProjectInfo getProjectInfo(String projectName) {
        if (projectName == null || projectName.trim().isEmpty()) {
            throw new IllegalArgumentException("项目名称不能为空");
        }
        
        try {
            ProjectInfo projectInfo = codeAnalysisDao.getProjectInfo(projectName);
            if (projectInfo == null) {
                log.warn("项目不存在: {}", projectName);
            }
            return projectInfo;
        } catch (Exception e) {
            log.error("获取项目信息失败: {}", projectName, e);
            throw new RuntimeException("获取项目信息失败", e);
        }
    }
    /**
     * 保存入口点信息
     *
     * @param entryPointInfo 入口点信息
     * @return 是否保存成功
     */
    public boolean saveEntryPointInfo(EntryPointInfo entryPointInfo) {
        return codeAnalysisDao.saveEntryPointInfo(entryPointInfo);
    }

    /**
     * 获取项目的所有入口点
     * @param projectName 项目名称
     * @return 入口点列表
     */
    public List<EntryPointInfo> getEntryPoints(String projectName) {
        try {
            return entryPointInfoMapper.getEntryPointsByProjectName(projectName);
        } catch (Exception e) {
            log.error("获取入口点信息失败: {}", projectName, e);
            return null;
        }
    }
    
    /**
     * 获取项目的所有类
     * @param projectName 项目名称
     * @return 类列表
     */
    public List<JavaClassInfo> getAllClasses(String projectName) {
        try {
            return javaClassInfoMapper.getByProjectName(projectName);
        } catch (Exception e) {
            log.error("获取类信息失败: {}", projectName, e);
            return null;
        }
    }

    public void saveEntryPointData(List<EntryPointInfo> entryPointInfos) {
        if(CollectionUtil.isEmpty(entryPointInfos)){
            log.warn("没有需要保存的入口点信息");
            return;
        }
        String projectName = entryPointInfos.get(0).getProjectName();
        // 1. 删除指定projectName下refreshable=true的入口点
        entryPointInfoMapper.deleteRefreshableByProjectName(projectName);
        // 2. 获取数据库中已存在的(className, methodName, packageName)
        List<EntryPointInfo> dbEntryList = entryPointInfoMapper.getEntryPointsByProjectName(projectName);
        java.util.Set<String> existKeySet = new java.util.HashSet<>();
        if (dbEntryList != null) {
            for (EntryPointInfo dbEntry : dbEntryList) {
                String key = dbEntry.getClassName() + "#" + dbEntry.getMethodName() + "#" + dbEntry.getPackageName();
                existKeySet.add(key);
            }
        }
        // 3. 筛选出数据库中不存在的入口点
        List<EntryPointInfo> toInsert = new java.util.ArrayList<>();
        for (EntryPointInfo entry : entryPointInfos) {
            String key = entry.getClassName() + "#" + entry.getMethodName() + "#" + entry.getPackageName();
            if (!existKeySet.contains(key)) {
                toInsert.add(entry);
            }
        }
        // 4. 分批插入
        if (!toInsert.isEmpty()) {
            int batchSize = 50;
            int total = toInsert.size();
            for (int i = 0; i < total; i += batchSize) {
                int end = Math.min(i + batchSize, total);
                List<EntryPointInfo> batch = toInsert.subList(i, end);
                entryPointInfoMapper.insertBatch(batch);
                log.info("已插入入口点信息: {}/{}", end, total);
            }
            log.info("批量插入{}条入口点信息", toInsert.size());
        } else {
            log.info("无新增入口点信息需要插入");
        }
    }

    /**
     * 批量分批插入类信息，每批最多50条
     */
    private void batchInsertClassInfo(List<JavaClassInfo> classInfoList) {
        if (CollectionUtil.isEmpty(classInfoList)) {
            return;
        }
        int batchSize = 50;
        int total = classInfoList.size();
        for (int i = 0; i < total; i += batchSize) {
            int end = Math.min(i + batchSize, total);
            List<JavaClassInfo> batch = classInfoList.subList(i, end);
            javaClassInfoMapper.insertBatch(batch);
            log.info("已插入类信息: {}/{}", end, total);
        }
    }

    public void saveClassInfo(List<JavaClassInfo> classInfoList) {
        if(CollectionUtil.isEmpty(classInfoList)){
            log.warn("没有需要保存的类信息");
            return;
        }
        String projectName = classInfoList.get(0).getProjectName();
        // 1. 删除指定projectName下refreshable=true的记录
        javaClassInfoMapper.deleteRefreshableByProjectName(projectName);
        // 2. 获取数据库中已存在的类(className, packageName)
        List<JavaClassInfo> dbClassList = javaClassInfoMapper.getByProjectName(projectName);
        java.util.Set<String> existKeySet = new java.util.HashSet<>();
        if (dbClassList != null) {
            for (JavaClassInfo dbClass : dbClassList) {
                String key = dbClass.getClassName() + "#" + dbClass.getPackageName();
                existKeySet.add(key);
            }
        }
        // 3. 筛选出数据库中不存在的类
        List<JavaClassInfo> toInsert = new java.util.ArrayList<>();
        for (JavaClassInfo classInfo : classInfoList) {
            String key = classInfo.getClassName() + "#" + classInfo.getPackageName();
            if (!existKeySet.contains(key)) {
                toInsert.add(classInfo);
            }
        }
        // 4. 分批插入
        if (!toInsert.isEmpty()) {
            batchInsertClassInfo(toInsert);
            log.info("批量插入{}条类信息", toInsert.size());
        } else {
            log.info("无新增类信息需要插入");
        }
    }

    /**
     * 保存方法信息
     */
    public void saveMethodInfo(List<JavaMethodInfo> methodInfos) {
        if (methodInfos == null || methodInfos.isEmpty()) {
            return;
        }
        String projectName = methodInfos.get(0).getProjectName();
        // 1. 删除指定projectName下refreshable=true的方法
        javaMethodInfoMapper.deleteRefreshableByProjectName(projectName);
        log.info("已删除项目[{}]的原有方法信息", projectName);
        // 2. 获取数据库中已存在的(className, methodName)
        List<JavaMethodInfo> dbMethodList = javaMethodInfoMapper.getByProjectName(projectName);
        java.util.Set<String> existKeySet = new java.util.HashSet<>();
        if (dbMethodList != null) {
            for (JavaMethodInfo dbMethod : dbMethodList) {
                String key = dbMethod.getClassName() + "#" + dbMethod.getMethodName();
                existKeySet.add(key);
            }
        }
        // 3. 筛选出数据库中不存在的方法
        List<JavaMethodInfo> toInsert = new java.util.ArrayList<>();
        for (JavaMethodInfo method : methodInfos) {
            String key = method.getClassName() + "#" + method.getMethodName();
            if (!existKeySet.contains(key)) {
                toInsert.add(method);
            }
        }
        // 4. 分批插入
        if (!toInsert.isEmpty()) {
            int batchSize = 50;
            int total = toInsert.size();
            for (int i = 0; i < total; i += batchSize) {
                int end = Math.min(i + batchSize, total);
                List<JavaMethodInfo> batch = toInsert.subList(i, end);
                javaMethodInfoMapper.insertBatch(batch);
                log.info("已插入方法信息: {}/{}", end, total);
            }
            log.info("批量插入{}条方法信息", toInsert.size());
        } else {
            log.info("无新增方法信息需要插入");
        }
    }

    public List<JavaMethodInfo> getAllMethods(String projectName) {
        return javaMethodInfoMapper.getByProjectName(projectName);
    }
}